//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

// dllentry.c
//
// This file is provide the entry point
// -- _DllMainCRTStartup() for elastos.dll.
//

#include <elatypes.h>
#include <eladef.h>
#include <stdlib.h>

_ELASTOS_NAMESPACE_USING

typedef void (__cdecl *PF)(void);
#if defined(_GNUC)

void initterm(PF *pfbegin);
EXTERN_C PF __CTOR_LIST__[];
EXTERN_C PF __DTOR_LIST__[];
#elif defined(_EVC) || defined(_MSVC)
EXTERN_C void __cdecl initterm(PF *pfbegin, PF *pfend);
EXTERN_C PF __xc_a[];
EXTERN_C PF __xc_z[];
EXTERN_C PF __xt_a[];
EXTERN_C PF __xt_z[];
#endif

typedef void (__cdecl * EXIT_FUNCTION)(void);

EXTERN_C _ELASTOS Boolean __stdcall DllMain(
                PVoid hDllHandle, UInt32 dwReason, PVoid preserved);

EXTERN_C _ELASTOS Boolean __stdcall _DllMainCRTStartup(
    PVoid hDllHandle,
    UInt32 dwReason,
    PVoid preserved)
{
    _ELASTOS Boolean ret;

    if (dwReason == DLL_PROCESS_ATTACH) {
#if defined(_GNUC)
        initterm(__CTOR_LIST__);
#elif defined(_EVC) || defined(_MSVC)
        initterm(__xc_a, __xc_z);
#else
#error unknown compiler
#endif
    }

    ret = DllMain(hDllHandle, dwReason, preserved);

    if (dwReason == DLL_PROCESS_DETACH) {
#if defined(_GNUC)
        initterm(__DTOR_LIST__);
#elif defined(_EVC) || defined(_MSVC)
        atexit((EXIT_FUNCTION)-1);
        initterm(__xt_a, __xt_z);
#else
#error unknown compiler
#endif
    }

    return ret;
}

#if defined(_GNUC)
void initterm(PF *pfbegin)
{
    // constructor and destructor should begin with 0xfffffff
    // and end of 0

    if (*pfbegin == (PF)-1)
        pfbegin ++;
    else {
        DebugBreak();
    }

    while (*pfbegin) {
        (**pfbegin)();
        pfbegin ++;
    }
}
#elif defined(_EVC) || defined(_MSVC)
EXTERN_C void __cdecl initterm(PF *pfbegin, PF *pfend)
{
    while (pfbegin < pfend) {
        if (*pfbegin != NULL) {
            (**pfbegin)();
        }
        pfbegin++;
    }
}
#endif
